package org.usyk;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.apache.commons.collections.CollectionUtils;

import java.io.*;
import java.util.*;

import static org.usyk.combinatorics.PositionalNotationUtil.numberInNumSystem;
import static org.usyk.util.NumbersFilter.isWellFormed;

/**
 * Created by IntelliJ IDEA.
 * User: Алексейка
 * Date: 18.02.12
 * Time: 16:08
 * To change this template use File | Settings | File Templates.
 */
public class OptimalRealization {

    public static final Double THRESHOLD = 0.05;
    public static final Double EPSILON = 0.0000000001;
    public static final int PLACES = 450;

    public static Map<Integer, Double> partyRaiting = new HashMap<Integer, Double>();

    static {
//        partyRaiting.put(0, 0.249);
//        partyRaiting.put(6, 0.236);
//        partyRaiting.put(1, 0.151);
//        partyRaiting.put(7, 0.111);
//        partyRaiting.put(2, 0.044);
//        partyRaiting.put(3, 0.077);
//        partyRaiting.put(9, 0.058);
//        partyRaiting.put(4, 0.025);
//        partyRaiting.put(5, 0.024);
//        partyRaiting.put(8, 0.025);
        partyRaiting.put(0, 0.264507422);
        partyRaiting.put(6, 0.245614035);
        partyRaiting.put(1, 0.151147099);
        partyRaiting.put(7, 0.094466937);
        partyRaiting.put(2, 0.05802969);
        partyRaiting.put(3, 0.087719298);
        partyRaiting.put(9, 0.039136302);
        partyRaiting.put(4, 0.028340081);
        partyRaiting.put(5, 0.009446694);
        partyRaiting.put(8, 0.021592443);
    }

    public static Map<Integer, Double> guarantedOneElementWinning = new HashMap<Integer, Double>();
    public static Map<Coalition, Double> guarantedWinning = new HashMap<Coalition, Double>();

    //todo move this logic to Coalition class
    public static Double getSumOfGuarantedWinningsForCoalition(Coalition coalition) {
        Double result = 0d;
        for (Integer i : coalition.getParticipantsSet()) {
            result += guarantedOneElementWinning.get(i);
        }
        return result;
    }

    public static Map<Integer, List<Integer>> groups;
    public static BiMap<String, Integer> parties = HashBiMap.create(10);

    static {

        groups = new HashMap<Integer, List<Integer>>();
        List<Integer> group1 = new ArrayList<Integer>();
        group1.add(0);
        group1.add(1);
        group1.add(2);
        group1.add(3);
        group1.add(4);
        group1.add(5);

        groups.put(0, group1);

        List<Integer> group2 = new ArrayList<Integer>();
        group2.add(6);
        group2.add(7);
        group2.add(8);
        group2.add(9);

        groups.put(1, group2);

        parties.put("BUT", 0);
        parties.put("FRONT", 1);
        parties.put("SVOBODA", 2);
        parties.put("UDAR", 3);
        parties.put("GRYCENKO", 4);
        parties.put("NASHAUKR", 5);
        parties.put("PR", 6);
        parties.put("KPU", 7);
        parties.put("NPU", 8);
        parties.put("TIGIPKO", 9);

    }

    // на входе мапа из номера группы в маску что МЕГА ТУПО!!!
    public static Set<Coalition> convertToGameSituation(Map<Integer, String> coalitionRepresentation) throws SkipCombinationException {
        Set<Coalition> result = new HashSet<Coalition>(10);

        Collection<Coalition> coalitions = new HashSet<Coalition>(10);
        for (Map.Entry<Integer, String> entry : coalitionRepresentation.entrySet()) {
            Integer numberOfGroup = entry.getKey();
            String mask = entry.getValue();
            if (isWellFormed(mask)) {
                coalitions.addAll(getCoalitions(numberOfGroup, mask));
            } else {
                throw new SkipCombinationException();
            }
        }

        for (Coalition coalition : coalitions) {
            Double rating = 0d;
            for (Integer i : coalition.getParticipantsSet()) {
                rating += partyRaiting.get(i);
            }
            coalition.setPreRating(rating);
            result.add(coalition);
        }

        return result;
    }

    // Возвращает мапу из коалиций в их выигрыши
    public static void calculateResultForGameSituation(Set<Coalition> coalitions) {
        Map<Integer, Double> result = new HashMap<Integer, Double>(10);

        //filter set for coalitions which rating is greater than threshold
        Set<Coalition> finalSituation = new HashSet<Coalition>(10);
        for (Coalition coalition : coalitions) {
            if (coalition.getPreRating() > THRESHOLD) {
                finalSituation.add(coalition);
            }
        }

        //считаем общий рейтинг партий, которые преодолели барьер
        Double wholeRating = 0d;
        for (Coalition coalition : finalSituation) {
            wholeRating += coalition.getPreRating();
        }

        // исходя из общего рейтинга получаем количество мест в парламенте для каждой коалиции
        for (Coalition coalition : finalSituation) {
            coalition.setGain(PLACES * (coalition.getPreRating() / wholeRating));
        }

    }

    public static Map<Integer, Double> calculateFairResultFromGameSituation(Map<Set<Integer>, Double> gameSituation) {
        Map<Integer, Double> result = new HashMap<Integer, Double>(10);

        //filter map for coalitions which rating is greater than threshold
        Map<Set<Integer>, Double> finalSituation = new HashMap<Set<Integer>, Double>(10);
        for (Map.Entry<Set<Integer>, Double> entry : gameSituation.entrySet()) {
            if (entry.getValue() > THRESHOLD) {
                finalSituation.put(entry.getKey(), entry.getValue());
            }
        }


        Double wholeRating = 0d;
        for (Double d : finalSituation.values()) {
            wholeRating += d;
        }

        //spravedlivoe raspredelenie
        for (Set<Integer> parties : finalSituation.keySet()) {
            Double percent = finalSituation.get(parties) / wholeRating;

            Double wholeSocOpros = 0d;
            for (Integer partyOfCoalition : parties) {
                wholeSocOpros += partyRaiting.get(partyOfCoalition);
            }

            for (Integer partyOfCoalition : parties) {
                result.put(partyOfCoalition, PLACES * (partyRaiting.get(partyOfCoalition) / wholeSocOpros) * (finalSituation.get(parties) / wholeRating));
            }

        }

        return result;
    }

    /**
     * If one party of the coalition cannot guarantee gain for itself
     * it should compromise gain for more powerful parties
     *
     * @param gameSituation
     * @return
     */
    public static Map<Integer, Double> calculateRealResultFromGameSituation(Map<Set<Integer>, Double> gameSituation) {
        Map<Integer, Double> result = new HashMap<Integer, Double>(10);

        //filter map for coalitions which rating is greater than threshold
        Map<Set<Integer>, Double> finalSituation = new HashMap<Set<Integer>, Double>(10);
        for (Map.Entry<Set<Integer>, Double> entry : gameSituation.entrySet()) {
            if (entry.getValue() > THRESHOLD) {
                finalSituation.put(entry.getKey(), entry.getValue());
            }
        }


        Double wholeRating = 0d;
        for (Double d : finalSituation.values()) {
            wholeRating += d;
        }

        //spravedlivoe raspredelenie
        for (Set<Integer> parties : finalSituation.keySet()) {

            //необходимо получить решение для этой коалиции если каждая партия по отдельности и
            //предоставить выигрыш слабым по остаточному принципу
            boolean isFair = true;
            for (Integer party : parties) {
                if (guarantedOneElementWinning.get(party) == 0d) {
                    isFair = false;
                }
            }

            Double percent = finalSituation.get(parties) / wholeRating;

            if (isFair) {

                Double wholeSocOpros = 0d;
                for (Integer partyOfCoalition : parties) {
                    wholeSocOpros += partyRaiting.get(partyOfCoalition);
                }

                for (Integer partyOfCoalition : parties) {
                    result.put(partyOfCoalition, PLACES * (partyRaiting.get(partyOfCoalition) / wholeSocOpros) * (finalSituation.get(parties) / wholeRating));
                }
            } else {
                //необходимо получить решение для этой коалиции если каждая партия по отдельности и
                //предоставить выигрыш слабым по остаточному принципу
                Map<Set<Integer>, Double> fairGameToConstruct = new HashMap<Set<Integer>, Double>(10);
                for (Set<Integer> partiesToInclude : finalSituation.keySet()) {
                    if (partiesToInclude != parties) {
                        fairGameToConstruct.put(partiesToInclude, finalSituation.get(partiesToInclude));
                    }
                }
                for (Integer party : parties) {
                    fairGameToConstruct.put(new HashSet<Integer>(Arrays.asList(party)), partyRaiting.get(party));
                }
                Map<Integer, Double> fairResult = calculateFairResultFromGameSituation(fairGameToConstruct);

                Set<Integer> partiesToPartition = new HashSet<Integer>(10);
                Double takenPlaces = 0d;
                for (Integer party : parties) {
                    if (guarantedOneElementWinning.get(party) == 0d) {
                        partiesToPartition.add(party);
                    } else {
                        result.put(party, fairResult.get(party));
                        takenPlaces += fairResult.get(party);
                    }
                }

                Double wholeSocOpros = 0d;
                for (Integer partyOfCoalition : partiesToPartition) {
                    wholeSocOpros += partyRaiting.get(partyOfCoalition);
                }

                Double places = percent * PLACES - takenPlaces;
                for (Integer partyOfCoalition : partiesToPartition) {
                    result.put(partyOfCoalition, places * (partyRaiting.get(partyOfCoalition) / wholeSocOpros));
                }

            }
        }

        return result;
    }

    public static Map<String, Map<Integer, Collection<Set<Integer>>>> maskGroupCache = new HashMap<String, Map<Integer, Collection<Set<Integer>>>>();

    public static Collection<Set<Integer>> getCoalitionsFromCache(String mask, Integer group) {
        return maskGroupCache.get(mask) != null ? maskGroupCache.get(mask).get(group) : null;
    }

    // метод позволяет получить коалиции в зависимости от группы партий
    public static Collection<Coalition> getCoalitions(Integer group, String mask) {

        //all actions are performed in assumption that mask is well formed
        int systemBase = mask.length();
        char[] array = mask.toCharArray();

        int offset = 0;

        // если груп несколько, то считаем порядковый номер группы offset, чтобы потом получить
        // правильные порядковые номера участников
        for (int j = 0; j < group; j++) {
            offset += groups.get(j).size();
        }

        Map<Character, Coalition> map = new HashMap<Character, Coalition>();

        for (int i = 0; i < systemBase; i++) {
            char c = array[i];
            if (!map.containsKey(c)) {
                map.put(c, new Coalition());
            }
            int number = i + offset;
            map.get(c).addPaticipant(number, parties.inverse().get(number));

        }
        return map.values();
    }


//   просто результат для неша и калла смородинского
//    public static void main(String[] args) throws IOException {
//        // System.out.println(6*6*6*6*6*6 * 4*4*4*4);
//        File f = new File("D://results.txt");
//        FileWriter writer = new FileWriter(f);
//
//
//        Map<Set<Set<Integer>>, Map<Integer, Double>> result = new HashMap<Set<Set<Integer>>, Map<Integer, Double>>();
//
//        int k = 0;
//        long tick = System.currentTimeMillis();
//        Map<String, Integer> coalitionRepresentation;
//        for (int i = 0; i < 4 * 4 * 4 * 4; i++) {
//            String coalition1 = numberInNumSystem(i, 4);
//            for (int j = 0; j < 6 * 6 * 6 * 6 * 6 * 6; j++) {
//                coalitionRepresentation = new HashMap<String, Integer>(2);
//                coalitionRepresentation.put(coalition1, 1);
//                String coalition0 = numberInNumSystem(j, 6);
//                coalitionRepresentation.put(coalition0, 0);
//                try {
//                    Map<Set<Integer>, Double> gameSituation = convertToGameSituation(coalitionRepresentation);
//
////                    Map<Integer, Double> temp = calculateFairResultFromGameSituation(gameSituation);
//                    Map<Integer, Double> temp = calculateRealResultFromGameSituation(gameSituation);
////                    writer.write(++k + " : " + temp + "\n");
//         //           System.out.println(++k + " : " + temp);
//                    result.put(gameSituation.keySet(), temp);
//
//                } catch (SkipCombinationException e) {
//                    //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
//                }
//            }
//
////            long tack = System.currentTimeMillis();
////            System.out.println(tack-tick);
//        }
//        writer.flush();
//        writer.close();
//        System.out.println("-===File is written===-");
//
//        f = new File("D://results_filtered.txt");
//        writer = new FileWriter(f);
//
//        double globalNashWinning = 0d;
//        double globalKalWinning = 0d;
//        Set<Set<Set<Integer>>> kalSmorodinskiyCoalitions = new HashSet<Set<Set<Integer>>>();
//        HashSet<Set<Set<Integer>>> nashCoalitions = new HashSet<Set<Set<Integer>>>();
//
//        for (Map.Entry<Set<Set<Integer>>, Map<Integer, Double>> entry : result.entrySet()) {
//            writer.write(Arrays.deepToString(entry.getKey().toArray()) + " = " + entry.getValue() + "\n");
//            double nash = nashWinning(entry.getValue());
//            if (Math.abs(globalNashWinning - nash) < EPSILON) {
//                nashCoalitions.add(entry.getKey());
//            } else if (globalNashWinning < nash) {
//                globalNashWinning = nash;
//                nashCoalitions = new HashSet<Set<Set<Integer>>>();
//                nashCoalitions.add(entry.getKey());
//            }
//
//            double kalSmorodinskiy = kalaSmorodinskogoWinning(entry.getValue());
//            if (Math.abs(globalKalWinning - kalSmorodinskiy) < EPSILON) {
//                kalSmorodinskiyCoalitions.add(entry.getKey());
//            } else if (globalKalWinning < kalSmorodinskiy) {
//                globalKalWinning = kalSmorodinskiy;
//                kalSmorodinskiyCoalitions = new HashSet<Set<Set<Integer>>>();
//                kalSmorodinskiyCoalitions.add(entry.getKey());
//            }
//
//
//        }
//
//        writer.flush();
//        writer.close();
//
//        System.out.println("-===Filtered file is written===-");
//
//        f = new File("D://results_nash.txt");
//        writer = new FileWriter(f);
//        writer.write("Nash value = " + globalNashWinning + "\n");
//        for (Set<Set<Integer>> coalition : nashCoalitions) {
//            writer.write(Arrays.deepToString(convertToNamedCoalition(coalition).toArray()) + "\n");
//        }
//        writer.flush();
//        writer.close();
//
//        System.out.println("-===Nash file is written===-");
//
//        f = new File("D://results_kal.txt");
//        writer = new FileWriter(f);
//
//        writer.write("Kal value = " + globalKalWinning + "\n");
//        for (Set<Set<Integer>> coalition : kalSmorodinskiyCoalitions) {
//            Set<Set<String>> namedCoalition = convertToNamedCoalition(coalition);
//            writer.write(Arrays.deepToString(namedCoalition.toArray()) + "\n");
//        }
//
//        writer.flush();
//        writer.close();
//
//        System.out.println("-===Kal file is written===-");
//
////        for (int i = 0; i < 6*6*6*6*6*6; i++) {
////            System.out.println(numberInNumSystem(i, 6));
////        }
//        long tack = System.currentTimeMillis();
//        System.out.println(tack - tick);
//
//
//    }

    public static Map<Integer,Integer> factorial = new HashMap<Integer, Integer>();
    static {
        factorial.put(1,1);
        factorial.put(2,2);
        factorial.put(3,6);
        factorial.put(4,24);
        factorial.put(5,120);
        factorial.put(6,720);
        factorial.put(7,5040);
        factorial.put(8,40320);
        factorial.put(9,362880);
        factorial.put(10,3628800);
    }

    public static void main(String[] args) throws IOException {
        // System.out.println(6*6*6*6*6*6 * 4*4*4*4);
        File f = new File("D://results.txt");
        FileWriter writer = new FileWriter(f);


        Map<Set<Set<Integer>>, Map<Integer, Double>> result = new HashMap<Set<Set<Integer>>, Map<Integer, Double>>();

        Map<Coalition, Double> pi = new HashMap<Coalition, Double>();

        int k = 0;
        long tick = System.currentTimeMillis();
        Map<Integer, String> coalitionRepresentation;
        for (int i = 0; i < 4 * 4 * 4 * 4; i++) {
            String coalition1 = numberInNumSystem(i, 4);
            for (int j = 0; j < 6 * 6 * 6 * 6 * 6 * 6; j++) {
                coalitionRepresentation = new HashMap<Integer, String>(2);
                String coalition0 = numberInNumSystem(j, 6);
                coalitionRepresentation.put(0, coalition0);
                coalitionRepresentation.put(1, coalition1);
                try {
                    // собирает все в один сет из коалиций (каждая коалиция уже имеет рейтинг)
                    Set<Coalition> coalitions = convertToGameSituation(coalitionRepresentation);

                    // Map<Integer, Double> temp = calculateFairResultFromGameSituation(gameSituation);
                    calculateResultForGameSituation(coalitions);

                    // заполнить мапу гарантированых выигрышей для одиночных коалиций
                    for (Coalition coalition : coalitions) {
                        if (coalition.size() == 1) {
                            Integer partyIndex = (Integer) coalition.getParticipantsSet().toArray()[0];
                            Double prevWin = guarantedOneElementWinning.get(partyIndex);
                            Double currWin = coalition.getGain();
                            if (prevWin == null || prevWin > currWin) {
                                guarantedOneElementWinning.put(partyIndex, currWin);
                            }
                        }
                        Double prevWin = guarantedWinning.get(coalition);
                        Double currWin = coalition.getGain();
                        if (prevWin == null || prevWin > currWin) {
                            guarantedWinning.put(coalition, currWin);
                        }
                    }
                } catch (SkipCombinationException e1) {
                    //
                }
            }
        }

        System.out.println("guarantedOneElementWinning = " + guarantedOneElementWinning);
        System.out.println("guarantedWinning.size() = " + guarantedWinning.size());
        
        // подсчитаем вектор Шепли для коалиций
        // 1) создадим мапу из одноэлементной коалиции в те, в которых она принимает участие
        Map<Coalition,Set<Coalition>> indexMap = new HashMap<Coalition, Set<Coalition>>();
        for (Coalition c : guarantedWinning.keySet()) {
            for (Map.Entry<Integer, String> party : c.getParticipants().entrySet()){
                Coalition coalition = new Coalition(party);
                Set<Coalition> coalitionSet = indexMap.get(coalition);
                if (coalitionSet==null) {
                    indexMap.put(coalition, new HashSet<Coalition>());
                }
                indexMap.get(coalition).add(c);
            }
        }

        // подсчет вектора шепли
        for (Map.Entry<Coalition,Set<Coalition>> entry : indexMap.entrySet()) {
            Double phi = 0d;
            for (Coalition c : entry.getValue()) {
                //todo debug
                if (c.size() > 1) {
                    Double temp = factorial.get(c.size()-1).doubleValue() * factorial.get(10 - c.size()).doubleValue() / factorial.get(10).doubleValue();
                    Coalition tempCoalitionWithoutPlayer = new Coalition(c);
                    Integer indexOfParticipant = (Integer) entry.getKey().getParticipantsSet().toArray()[0];
                    tempCoalitionWithoutPlayer.excludeParticipant(indexOfParticipant);
                    temp = temp * (guarantedWinning.get(c) - guarantedWinning.get(tempCoalitionWithoutPlayer));
                    phi += temp;
                }
            }
            System.out.println("phi[" + entry.getKey().getParticipants() + "] = " + phi);
        }
        
        for (int i = 0; i < 4 * 4 * 4 * 4; i++) {
            String coalition1 = numberInNumSystem(i, 4);
            for (int j = 0; j < 6 * 6 * 6 * 6 * 6 * 6; j++) {
                coalitionRepresentation = new HashMap<Integer, String>(2);
                String coalition0 = numberInNumSystem(j, 6);
                coalitionRepresentation.put(0, coalition0);
                coalitionRepresentation.put(1, coalition1);
                try {
                    // собирает все в один сет из коалиций (каждая коалиция уже имеет рейтинг)
                    Set<Coalition> coalitions = convertToGameSituation(coalitionRepresentation);

                    // Map<Integer, Double> temp = calculateFairResultFromGameSituation(gameSituation);
                    calculateResultForGameSituation(coalitions);

                    //смольяков
                    for (Coalition coalition : coalitions) {
                        // String coalition = convertFromCoalitionRepresentation(resultForCoalition.getKey());
                        int numberOfParticipants = coalition.size();
                        Double piResult = (coalition.getGain() - getSumOfGuarantedWinningsForCoalition(coalition))
                                / numberOfParticipants;
                        if (pi.containsKey(coalition)) {
                            if (pi.get(coalition) > piResult) {
                                pi.put(coalition, piResult);
                            }
                        } else {
                            pi.put(coalition, piResult);
                        }
                    }


//                    writer.write(++k + " : " + temp + "\n");
                    //           System.out.println(++k + " : " + temp);
                    //  result.put(gameSituation.keySet(), temp);

                } catch (SkipCombinationException e) {
                    //e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                }
            }

//            long tack = System.currentTimeMillis();
//            System.out.println(tack-tick);
        }
        writer.flush();
        writer.close();
        System.out.println("-===File is written===-");

        Map<Coalition, Double> finalPiResult = new HashMap<Coalition, Double>();
        System.out.println("COALITIONS : ");
        while (!pi.isEmpty()) {

            Map.Entry<Coalition, Double> maxCoalition = getMaxCoalition(pi);

            excludeFromPi(maxCoalition.getKey(), pi);
            finalPiResult.put(maxCoalition.getKey(), maxCoalition.getValue());
            for (int i : maxCoalition.getKey().getParticipantsSet()) {
                System.out.print(parties.inverse().get(i) + " + ");
            }
            System.out.println(". pi = " + maxCoalition.getValue());

        }

        System.out.println("Results = " + finalPiResult);

        f = new File("D://results_filtered.txt");
        writer = new FileWriter(f);

        double globalNashWinning = 0d;
        double globalKalWinning = 0d;
        Set<Set<Set<Integer>>> kalSmorodinskiyCoalitions = new HashSet<Set<Set<Integer>>>();
        HashSet<Set<Set<Integer>>> nashCoalitions = new HashSet<Set<Set<Integer>>>();

        for (Map.Entry<Set<Set<Integer>>, Map<Integer, Double>> entry : result.entrySet()) {
            writer.write(Arrays.deepToString(entry.getKey().toArray()) + " = " + entry.getValue() + "\n");
            double nash = nashWinning(entry.getValue());
            if (Math.abs(globalNashWinning - nash) < EPSILON) {
                nashCoalitions.add(entry.getKey());
            } else if (globalNashWinning < nash) {
                globalNashWinning = nash;
                nashCoalitions = new HashSet<Set<Set<Integer>>>();
                nashCoalitions.add(entry.getKey());
            }

            double kalSmorodinskiy = kalaSmorodinskogoWinning(entry.getValue());
            if (Math.abs(globalKalWinning - kalSmorodinskiy) < EPSILON) {
                kalSmorodinskiyCoalitions.add(entry.getKey());
            } else if (globalKalWinning < kalSmorodinskiy) {
                globalKalWinning = kalSmorodinskiy;
                kalSmorodinskiyCoalitions = new HashSet<Set<Set<Integer>>>();
                kalSmorodinskiyCoalitions.add(entry.getKey());
            }


        }

        writer.flush();
        writer.close();

        System.out.println("-===Filtered file is written===-");

        f = new File("D://results_nash.txt");
        writer = new FileWriter(f);
        writer.write("Nash value = " + globalNashWinning + "\n");
        for (Set<Set<Integer>> coalition : nashCoalitions) {
            writer.write(Arrays.deepToString(convertToNamedCoalition(coalition).toArray()) + "\n");
        }
        writer.flush();
        writer.close();

        System.out.println("-===Nash file is written===-");

        f = new File("D://results_kal.txt");
        writer = new FileWriter(f);

        writer.write("Kal value = " + globalKalWinning + "\n");
        for (Set<Set<Integer>> coalition : kalSmorodinskiyCoalitions) {
            Set<Set<String>> namedCoalition = convertToNamedCoalition(coalition);
            writer.write(Arrays.deepToString(namedCoalition.toArray()) + "\n");
        }

        writer.flush();
        writer.close();

        System.out.println("-===Kal file is written===-");

//        for (int i = 0; i < 6*6*6*6*6*6; i++) {
//            System.out.println(numberInNumSystem(i, 6));
//        }
        long tack = System.currentTimeMillis();
        System.out.println(tack - tick);


    }

    private static Map.Entry<Coalition, Double> getMaxCoalition(Map<Coalition, Double> pi) {
        Map.Entry<Coalition, Double> maxEntry = null;

        for (Map.Entry<Coalition, Double> entry : pi.entrySet()) {
            if (maxEntry == null || entry.getValue() > maxEntry.getValue()) {
                maxEntry = entry;
            }
        }
        return maxEntry;
    }

    private static void excludeFromPi(Coalition coalition, Map<Coalition, Double> pi) {

        pi.remove(coalition);
        Set<Coalition> coalitionsToRemove = new HashSet<Coalition>();
        for (Coalition c : pi.keySet()) {
            if (CollectionUtils.intersection(c.getParticipantsSet(), coalition.getParticipantsSet()).size() > 0) {
                coalitionsToRemove.add(c);
            }
        }
        for (Coalition s : coalitionsToRemove) {
            pi.remove(s);
        }

    }

    private static boolean isIntersecting(String coalition, String key) {
        for (int i = 0; i < coalition.length(); i++) {
            if (coalition.toCharArray()[i] == '1' && key.toCharArray()[i] == '1') {
                return true;
            }
        }
        return false;
    }

    private static Set<Set<String>> convertToNamedCoalition(Set<Set<Integer>> coalition) {
        Set<Set<String>> namedCoalition = new HashSet<Set<String>>();
        for (Set<Integer> parties1 : coalition) {
            Set<String> names = new HashSet<String>();
            for (Integer party : parties1) {
                names.add(parties.inverse().get(party));
            }
            namedCoalition.add(names);
        }
        return namedCoalition;
    }

    public static Double nashWinning(Map<Integer, Double> realWinning) {
        double alpha = 1.0 / parties.size();
        double result = 1d;
        for (Integer i : guarantedOneElementWinning.keySet()) {
            if (realWinning.get(i) != null) {
                result *= Math.pow((realWinning.get(i) - guarantedOneElementWinning.get(i)), alpha);
            } else {
                return 0d;
            }
        }
        return result;
    }

    public static Double kalaSmorodinskogoWinning(Map<Integer, Double> realWinning) {

        double result = (realWinning.get(0) - guarantedOneElementWinning.get(0));

        for (Integer i : guarantedOneElementWinning.keySet()) {
            if (realWinning.get(i) != null) {
                result = Math.min(result, (realWinning.get(i) - guarantedOneElementWinning.get(i)));
            } else {
                return 0d;
            }
        }

        return result;
    }

}
